package cn.zifangsky.jvm.part2.threadlocal.demo1;

import cn.zifangsky.jvm.part2.threadlocal.User;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 测试{@link ThreadLocal}的使用
 *
 * @author zifangsky
 * @date 2020/7/11
 * @since 1.0.0
 */
public class Demo {
    /**
     * 定义一个ThreadLocal
     */
    private static final ThreadLocal<User> RESOURCES = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        int threadNum = 3;
        AtomicInteger count = new AtomicInteger(0);
        //定义一个循环栅栏
        CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum);
        //定义一个线程池
        ExecutorService threadPool = new ThreadPoolExecutor(threadNum, threadNum,
                0L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(), r-> {

            Thread thread = new Thread(r);
            thread.setDaemon(true);
            thread.setName("thread-" + count.getAndIncrement());

            return thread;
        },new ThreadPoolExecutor.AbortPolicy());

        //依次提交线程
        for(int i = 0; i < threadNum; i++){
            threadPool.submit(new Task(cyclicBarrier, i));
        }

        Thread.sleep(5000);
        threadPool.shutdown();
    }


    static class Task implements Runnable {
        private CyclicBarrier cyclicBarrier;

        private User user;

        public Task(CyclicBarrier cyclicBarrier, int index) {
            this.cyclicBarrier = cyclicBarrier;
            this.user = new User(index, String.format("name_%d", index));
        }

        @Override
        public void run() {

            try {
                //1. 等待所有线程统一把 user 对象存到ThreadLocal
                cyclicBarrier.await();

                //2. 把 user 对象存到ThreadLocal
                this.prepare();

                //3. 再次等待
                cyclicBarrier.await();

                //4. 统一执行任务
                this.doTask();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

        private void prepare(){
            RESOURCES.set(this.user);
        }

        private void doTask(){
            System.out.println(String.format("Thread[%s] doTask: index=%s",
                    Thread.currentThread().getName(), RESOURCES.get().getId()));
        }
    }






}
